2008-06-08 02:33:00
Absolut Chess v1.5 是一个国际象棋软件。下载的版本是演示版,有 10 次使用次数限制,否则将不能运行。演示版不能输入注册码(但实际上功能存在的,被隐藏掉了)。
补丁部分
首先是去掉使用次数限制。 10 次以后会跳出一个框,在 ·DialogBoxParamA· 上设断点顺利截到。
10040F9EF 833D 50834300 00 cmp dword ptr [438350], 0
20040F9F6 0F84 39000000 je 0040FA35
30040F9FC 6A 00 push 0 ; /lParam = NULL
40040F9FE 68 0F104000 push 0040100F ; |DlgProc = AbsolutC.0040100F
50040FA03 8B45 08 mov eax, dword ptr [ebp+8] ; |
60040FA06 50 push eax ; |hOwner
70040FA07 68 30874300 push 00438730 ; |pTemplate = "DLG_BUY"
80040FA0C A1 848B4500 mov eax, dword ptr [458B84] ; |
90040FA11 50 push eax ; |hInst => 00400000
100040FA12 FF15 E0284700 call dword ptr [<&USER32.DialogB>; /DialogBoxParamA
110040FA18 8945 E4 mov dword ptr [ebp-1C], eax
120040FA1B 837D E4 00 cmp dword ptr [ebp-1C], 0
130040FA1F 0F85 10000000 jnz 0040FA35
140040FA25 6A 00 push 0 ; /lParam = 0
150040FA27 6A 00 push 0 ; |wParam = 0
160040FA29 6A 02 push 2 ; |Message = WM_DESTROY
170040FA2B 8B45 08 mov eax, dword ptr [ebp+8] ; |
180040FA2E 50 push eax ; |hWnd
190040FA2F FF15 E4284700 call dword ptr [<&USER32.SendMes>; /SendMessageA
200040FA35 833D 985E4400 00 cmp dword ptr [445E98], 0
这部分第一行可以看到,根据 [438350] 是否为 0 来判断要不要显式使用次数已到的框。 再往上看:
10040F8D9 833D 948C4500 0A cmp dword ptr [458C94], 0A
20040F8E0 0F8E 0A000000 jle 0040F8F0
30040F8E6 C705 50834300 01000 mov dword ptr [438350], 1
40040F8F0 C705 40834300 00000 mov dword ptr [438340], 0
50040F8FA E9 9F000000 jmp 0040F99E
如果 [458C94] <= 0Ah(10),就跳过给 [438350] 赋为 1 的那句。 由此推断,[458C94] 里面是当前使用次数。 重新开始调试,给 00458C94 设置内存写入硬件断点。 截到读取注册表写入内存变量部分如下:
10040E37E C785 0CFCFFFF 04000 mov dword ptr [ebp-3F4], 4
20040E388 8D85 0CFCFFFF lea eax, dword ptr [ebp-3F4]
30040E38E 50 push eax ; /pBufSize
40040E38F 8D85 10FCFFFF lea eax, dword ptr [ebp-3F0] ; |
50040E395 50 push eax ; |Buffer
60040E396 6A 00 push 0 ; |pValueType = NULL
70040E398 6A 00 push 0 ; |Reserved = NULL
80040E39A 68 48854300 push 00438548 ; |ValueName = "cvezes"
90040E39F 8B85 14FCFFFF mov eax, dword ptr [ebp-3EC] ; |
100040E3A5 50 push eax ; |hKey
110040E3A6 FF15 74254700 call dword ptr [<&ADVAPI32.RegQu>; /RegQueryValueExA
120040E3AC 8985 BCF7FFFF mov dword ptr [ebp-844], eax
130040E3B2 83BD BCF7FFFF 00 cmp dword ptr [ebp-844], 0
140040E3B9 0F85 16000000 jnz 0040E3D5
150040E3BF 8B85 10FCFFFF mov eax, dword ptr [ebp-3F0] ; 注册表中的值
160040E3C5 35 F4FE0E00 xor eax, 0EFEF4 ; 0xEFEF4^0xEFEF4=0, 0xEFEF4^0xEFEFF=0Ah
170040E3CA A3 948C4500 mov dword ptr [458C94], eax ; 写到内存变量
180040E3CF FF05 948C4500 inc dword ptr [458C94] ; 使用次数加1
于是可以把 eax, 0EFEF4 这据改掉,改为 xor eax, eax,这样每次都是第一次了。
第一处改动:0040E3C5 . 35 F4FE0E00 xor eax, 0EFEF4
改为
10040E3C5 33C0 xor eax, eax
20040E3C7 90 nop
30040E3C8 90 nop
40040E3C9 90 nop
文件修补:0000D7C5 35 F4 FE 0E 00 -> 33 C0 90 90 90
接下来是两处输入注册码的按钮。
先是 10 次使用满了跳出来的那个框里。
按下输入注册码按钮,出来一个框说演示版不能注册。这个框是 MessageBox。
在 MessageBoxA 上设断点,调用处:
10041F7F1 837D F4 02 cmp dword ptr [ebp-C], 2
20041F7F5 0F84 72FFFFFF je 0041F76D
看到 0041F76D 附近:
10041F76D > /6A 30 push 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
20041F76F . |68 50954300 push 00439550 ; |Title = "Demo Version"
30041F774 . |68 60954300 push 00439560 ; |Text = "Operation do not allowed in this demo.",LF,LF,"Buy the full version online!",LF,LF,"http://www.overlans.com/shop.php",LF,LF,"Only $ 12"
40041F779 . |8B45 08 mov eax, dword ptr [ebp+8] ; |
50041F77C . |50 push eax ; |hOwner
60041F77D . |FF15 54284700 call dword ptr [<&USER32.MessageBoxA>>; /MessageBoxA
70041F783 . |68 D4954300 push 004395D4 ; /Title = "Microsoft Internet Explorer"
80041F788 . |6A 00 push 0 ; |Class = 0
90041F78A . |6A 00 push 0 ; |hAfterWnd = NULL
100041F78C . |6A 00 push 0 ; |hParent = NULL
110041F78E . |FF15 68284700 call dword ptr [<&USER32.FindWindowEx>; /FindWindowExA
120041F794 . |8945 FC mov dword ptr [ebp-4], eax
130041F797 . |6A 01 push 1 ; /IsShown = 1
140041F799 . |6A 00 push 0 ; |DefDir = NULL
150041F79B . |6A 00 push 0 ; |Parameters = NULL
160041F79D . |68 F0954300 push 004395F0 ; |FileName = "http://www.overlans.com/shop.php"
170041F7A2 . |68 14964300 push 00439614 ; |Operation = "open"
180041F7A7 . |8B45 FC mov eax, dword ptr [ebp-4] ; |
190041F7AA . |50 push eax ; |hWnd
200041F7AB . |FF15 1C284700 call dword ptr [<&SHELL32.ShellExecut>; /ShellExecuteA
210041F7B1 . |E9 27000000 jmp 0041F7DD
220041F7B6 . |6A 00 push 0 ; /lParam = NULL
230041F7B8 . |68 90114000 push 00401190 ; |DlgProc = AbsolutC.00401190
240041F7BD . |8B45 08 mov eax, dword ptr [ebp+8] ; |
250041F7C0 . |50 push eax ; |hOwner
260041F7C1 . |68 1C964300 push 0043961C ; |pTemplate = "DLG_LICENCA"
270041F7C6 . |A1 848B4500 mov eax, dword ptr [458B84] ; |
280041F7CB . |50 push eax ; |hInst => NULL
290041F7CC . |FF15 E0284700 call dword ptr [<&USER32.DialogBoxPar>; /DialogBoxParamA
300041F7D2 . |50 push eax ; /Result
310041F7D3 . |8B45 08 mov eax, dword ptr [ebp+8] ; |
320041F7D6 . |50 push eax ; |hWnd
330041F7D7 . |FF15 F8284700 call dword ptr [<&USER32.EndDialog>] ; /EndDialog
340041F7DD > |E9 2B000000 jmp 0041F80D
看到先跳出一个框,再打开一个网址。注意到紧跟在它后面的 0041F7B6,DLG_LICENCA 这个名字好像是我们期待的。把 0041F7F5 的跳转改为 je 0041F7B6 试试看,果然见到了那个框。
第二处改动:0041F7F5 0F 84 72 FF FF FF (je long 0041F76D) 改为 0F 84 BB FF FF FF (je long 0041F7B6)
也可改为 74 BF 90 90 90 90 (je short 0041F7B6)
文件修补:0001EBF7 72 -> BB
再是帮助菜单里的注册菜单项。
同样截 MessageBoxA,可以找到 00410594 这个函数是调用者。它显示 Demo 版不可注册,并打开网址。
跟上面一模一样,紧跟在其后的 004105DD 用于弹出注册框用于输入。
向上看,找到
100411666 8B85 FCFBFFFF mov eax, dword ptr [ebp-404] ; eax=[0012F9Ec]=0000001A
20041166C 33C9 xor ecx, ecx
30041166E 8A88 1F174100 mov cl, byte ptr [eax+41171F] ; cl=[41171F+1A]=[411739]=12
400411674 FF248D 7B1641 jmp dword ptr [ecx*4+41167B] ; [ecx*4+41167B]=[004116C3]=00410594
004116C3 处存放着这个地址。于是第三处改动:把 004116C3 处 94 05 41 00 改为 DD 05 41 00 就好了。文件修补:00010AC3 94 -> DD
下面来分析注册判断流程。
随便输注册码,截 MessageBoxA。下面这段是相关内容和分析:
10041FEE9 8D85 38FFFFFF lea eax, dword ptr [ebp-C8] ; 注册码 "1234"
20041FEEF 50 push eax ; 00401177 参数三
30041FEF0 8D45 9C lea eax, dword ptr [ebp-64] ; 用户名 "kjj"
40041FEF3 50 push eax ; 00421B30 参数
50041FEF4 E8 371C0000 call 00421B30 ; 求用户名长度?
60041FEF9 83C4 04 add esp, 4 ; 这里看出上面这个函数只有一个参数, "1234" 不是它的
70041FEFC 50 push eax ; eax=3, 00401177 参数二
80041FEFD 8D45 9C lea eax, dword ptr [ebp-64] ; [ebp-64]="kjj"
90041FF00 50 push eax ; 00401177 参数一
100041FF01 E8 7112FEFF call 00401177 ;
11{
12 00401177 E9 F0CD0000 jmp 0040DF6C
13
14 0040DF6C 55 push ebp
15 0040DF6D 8BEC mov ebp, esp
16 0040DF6F 83EC 24 sub esp, 24
17 0040DF72 53 push ebx
18 0040DF73 56 push esi
19 0040DF74 57 push edi
20 0040DF75 837D 0C 00 cmp dword ptr [ebp+C], 0 ; [ebp+C]=00000003, 用户名长度
21 0040DF79 0F8F 07000000 jg 0040DF86
22 0040DF7F 33C0 xor eax, eax
23 0040DF81 E9 80000000 jmp 0040E006
24 0040DF86 8B45 10 mov eax, dword ptr [ebp+10] ; [ebp+10]=[0012F614]=0012F62C="1234"
25 0040DF89 50 push eax ; 004012A8 的参数
26 0040DF8A E8 1933FFFF call 004012A8 ; 判断是否是 20 个万能注册码之一
27 {
28 004012A8 E9 C3C50000 jmp 0040D870
29
30 0040D870 55 push ebp
31 0040D871 8BEC mov ebp, esp
32 0040D873 83EC 04 sub esp, 4
33 0040D876 53 push ebx
34 0040D877 56 push esi
35 0040D878 57 push edi
36 0040D879 C745 FC 00000 mov dword ptr [ebp-4], 0 ; 这里把 [ebp-4] 弄成 0 了
37 0040D880 E9 03000000 jmp 0040D888
38 0040D885 FF45 FC inc dword ptr [ebp-4] ; 循环首, [ebp-4] 加 1
39 0040D888 A1 0C834300 mov eax, dword ptr [43830C]
40 0040D88D 3945 FC cmp dword ptr [ebp-4], eax
41 0040D890 0F8D 34000000 jge 0040D8CA
42 0040D896 8B45 08 mov eax, dword ptr [ebp+8] ; eax=[0012F400]="1234", 输入的注册码
43 0040D899 50 push eax ; 参数二
44 0040D89A 8B45 FC mov eax, dword ptr [ebp-4] ; eax=[ebp-4]
45 ; 1st: 刚才它被弄成 0 了, 于是 eax=0
46 0040D89D 03C0 add eax, eax ; eax=eax*2=[ebp-4]*2
47 0040D89F 8D0440 lea eax, dword ptr [eax+eax*2] ; eax=eax*3=[ebp-4]*6
48 0040D8A2 8D0480 lea eax, dword ptr [eax+eax*4] ; eax=eax*5=[ebp-4]*1E, 于是这里都是 0
49 0040D8A5 05 887F4300 add eax, 00437F88 ; 00437F88="Ab200001FRvGKF"
50 ; 这里有一张表:
51 ; 00437F88+ 0*1E: Ab200001FRvGKF
52 ; 00437F88+ 1*1E: Ab20001Mdvl6Il
53 ; 00437F88+ 2*1E: Ab20002qMv1oxy
54 ; 00437F88+ 3*1E: Ab20003C9kz5Kj
55 ; 00437F88+ 4*1E: Ab20004oXz3iYB
56 ; 00437F88+ 5*1E: Ab20005v63uo5b
57 ; 00437F88+ 6*1E: Ab20006xx6wmGk
58 ; 00437F88+ 7*1E: Ab20007iXrxYgx
59 ; 00437F88+ 8*1E: Ab20008CAO55EP
60 ; 00437F88+ 9*1E: Ab20009TUwNMYe
61 ; 00437F88+ A*1E: Ab20010askrZO9
62 ; 00437F88+ B*1E: Ab20011Q6VvIYZ
63 ; 00437F88+ C*1E: Ab200122PGq2NF
64 ; 00437F88+ D*1E: Ab20013KuI3ByH
65 ; 00437F88+ E*1E: Ab20014hGZnATH
66 ; 00437F88+ F*1E: Ab20015CIZD4Ji
67 ; 00437F88+10*1E: Ab20016qGqvpsn
68 ; 00437F88+11*1E: Ab200179Fq3nts
69 ; 00437F88+12*1E: Ab20018QLHV24h
70 ; 00437F88+13*1E: Ab20019nbbma0w
71 0040D8AA 50 push eax ; 参数一, "Ab200001FRvGKF"
72 0040D8AB E8 F0410100 call 00421AA0 ; 这里面就是简单的字符串比较,害得我看了半天
73 0040D8B0 83C4 08 add esp, 8
74 0040D8B3 85C0 test eax, eax
75 0040D8B5 0F85 0A000000 jnz 0040D8C5
76 0040D8BB B8 01000000 mov eax, 1 ; 如果相同, 令 eax=1
77 0040D8C0 E9 0C000000 jmp 0040D8D1 ; 跳到后面, 跳出这个函数, 这个函数返回值就是 1 了
78 0040D8C5 E9 BBFFFFFF jmp 0040D885
79 0040D8CA 33C0 xor eax, eax
80 0040D8CC E9 00000000 jmp 0040D8D1
81 0040D8D1 5F pop edi
82 0040D8D2 5E pop esi
83 0040D8D3 5B pop ebx
84 0040D8D4 C9 leave
85 0040D8D5 C3 retn
86 }
87 0040DF8F 83C4 04 add esp, 4
88 0040DF92 85C0 test eax, eax
89 0040DF94 0F84 0A000000 je 0040DFA4 ; 如果不是万能注册码, 跳过下面两行
90 0040DF9A B8 01000000 mov eax, 1 ; 如果是万能注册码, 令 eax=1
91 0040DF9F E9 62000000 jmp 0040E006 ; 跳到后面, 跳出函数
92 ; 下面是非万能注册码时的处理
93 0040DFA4 E8 2E31FFFF call 004010D7 ; 把字母和数字数了个遍
94 ; [462658]=0000003E(62), al='Z'
95 0040DFA9 8D45 DC lea eax, dword ptr [ebp-24] ; [ebp-24]=[0012F5E0], 缓冲区, 参数三
96 0040DFAC 50 push eax
97 0040DFAD 8B45 0C mov eax, dword ptr [ebp+C] ; eax=3, 用户名长度, 参数二
98 0040DFB0 50 push eax
99 0040DFB1 8B45 08 mov eax, dword ptr [ebp+8] ; eax="kjj", 用户名, 参数一
100 0040DFB4 50 push eax
101 0040DFB5 E8 1133FFFF call 004012CB ; 算法在这里, 详细内容见下面
102 ; [ebp-24]="CH&aIaJaIaIaJaIaIaKxA9"
103 0040DFBA 83C4 0C add esp, 0C
104 0040DFBD C745 FC 00000 mov dword ptr [ebp-4], 0
105 0040DFC4 E9 03000000 jmp 0040DFCC
106 0040DFC9 FF45 FC inc dword ptr [ebp-4] ; 这个循环用来比较注册码是否正确
107 0040DFCC 837D FC 12 cmp dword ptr [ebp-4], 12 ; 仅仅比较前 18 位
108 0040DFD0 0F8D 26000000 jge 0040DFFC
109 0040DFD6 8B45 FC mov eax, dword ptr [ebp-4]
110 0040DFD9 8B4D 10 mov ecx, dword ptr [ebp+10]
111 0040DFDC 0FBE0408 movsx eax, byte ptr [eax+ecx]
112 0040DFE0 8B4D FC mov ecx, dword ptr [ebp-4]
113 0040DFE3 0FBE4C0D DC movsx ecx, byte ptr [ebp+ecx-24]
114 0040DFE8 3BC1 cmp eax, ecx
115 0040DFEA 0F84 07000000 je 0040DFF7
116 0040DFF0 33C0 xor eax, eax
117 0040DFF2 E9 0F000000 jmp 0040E006
118 0040DFF7 E9 CDFFFFFF jmp 0040DFC9
119 0040DFFC B8 01000000 mov eax, 1
120 0040E001 E9 00000000 jmp 0040E006
121 0040E006 5F pop edi
122 0040E007 5E pop esi
123 0040E008 5B pop ebx
124 0040E009 C9 leave
125 0040E00A C3 retn
126}
1270041FF06 83C4 0C add esp, 0C ; 这里看出这个函数是三个参数
1280041FF09 85C0 test eax, eax
1290041FF0B 0F84 56000000 je 0041FF67 ; 无效注册码最后看注册算法这个函数。
130004012CB E9 3DC80000 jmp 0040DB0D
最后来看算注册码的函数。
10040DB0D 55 push ebp
20040DB0E 8BEC mov ebp, esp
3 ; 传入参数
4 ; [ebp+8]: char *username
5 ; [ebp+C]: int length
6 ; [ebp+10]: char *buffer
70040DB10 83EC 10 sub esp, 10 ; 4 个局部变量, 记为 int var[4]
80040DB13 53 push ebx
90040DB14 56 push esi
100040DB15 57 push edi
110040DB16 C745 F0 03000 mov dword ptr [ebp-10], 3 ; [ebp-10]=0012F5B0=00000003, var[0]=3
120040DB1D 837D 0C 00 cmp dword ptr [ebp+C], 0 ; 判断用户名是否零长度
130040DB21 0F8F 05000000 jg 0040DB2C
140040DB27 E9 4F010000 jmp 0040DC7B
150040DB2C E8 A635FFFF call 004010D7 ; 又是这个函数, [462658]=0000003E, al='Z'
160040DB31 A0 807F4300 mov al, byte ptr [437F80] ; [437F80]='C'
170040DB36 8B4D 10 mov ecx, dword ptr [ebp+10] ; 缓冲区地址, 刚才的第三个参数
180040DB39 8801 mov byte ptr [ecx], al
190040DB3B A0 817F4300 mov al, byte ptr [437F81] ; [437F81]='H'
200040DB40 8B4D 10 mov ecx, dword ptr [ebp+10]
210040DB43 8841 01 mov byte ptr [ecx+1], al
220040DB46 A0 827F4300 mov al, byte ptr [437F82] ; [437F82]='&'
230040DB4B 8B4D 10 mov ecx, dword ptr [ebp+10]
240040DB4E 8841 02 mov byte ptr [ecx+2], al ; 把 "CH&" 拷到缓冲区
250040DB51 C745 F4 03000 mov dword ptr [ebp-C], 3 ; [ebp-C]=00000003, var[1]=3, var[1] 记为 i
260040DB58 E9 03000000 jmp 0040DB60 ; 进入循环
270040DB5D FF45 F4 inc dword ptr [ebp-C] ; 循环首
280040DB60 837D F4 12 cmp dword ptr [ebp-C], 12 ; 一直循环到 i>=12,循环 15 次
290040DB64 0F8D 97000000 jge 0040DC01
300040DB6A 8B45 F4 mov eax, dword ptr [ebp-C] ; eax=i=3
310040DB6D 99 cdq ; edx=0
320040DB6E F77D 0C idiv dword ptr [ebp+C] ; eax=i/length=1, edx=i%length=0
330040DB71 8955 FC mov dword ptr [ebp-4], edx ; var[3]=edx=i%length=0, var[3] 记为 r1
340040DB74 8B45 F4 mov eax, dword ptr [ebp-C] ; eax=i=3
350040DB77 0345 F0 add eax, dword ptr [ebp-10] ; eax=eax+var[0]=eax+3=6
360040DB7A 99 cdq ; edx=0
370040DB7B F77D 0C idiv dword ptr [ebp+C] ; eax=(i+3)/length=2, edx=(i+3)%length=0
380040DB7E 8955 F8 mov dword ptr [ebp-8], edx ; var[2]=edx=(i+3)%length=0, var[2] 记为 r2
390040DB81 8B45 F4 mov eax, dword ptr [ebp-C] ; eax=i=3
400040DB84 99 cdq ; edx=0
410040DB85 33C2 xor eax, edx ; eax=3
420040DB87 2BC2 sub eax, edx ; eax=3
430040DB89 83E0 01 and eax, 1 ; eax=1
440040DB8C 33C2 xor eax, edx ; eax=1
450040DB8E 2BC2 sub eax, edx ; eax=1
46 ; 这段是判断 i 的奇偶
470040DB90 0F84 34000000 je 0040DBCA
480040DB96 8B45 F8 mov eax, dword ptr [ebp-8] ; eax=r2=0
490040DB99 8B4D 08 mov ecx, dword ptr [ebp+8] ; ecx=username
500040DB9C 0FBE0408 movsx eax, byte ptr [eax+ecx] ; eax=username[r2]
510040DBA0 8B4D FC mov ecx, dword ptr [ebp-4] ; ecx=r1
520040DBA3 8B55 08 mov edx, dword ptr [ebp+8] ; edx=username
530040DBA6 320411 xor al, byte ptr [ecx+edx] ; al=al^username[r1]=username[r2]^username[r2]=0
540040DBA9 33C9 xor ecx, ecx ; ecx=0
550040DBAB 8AC8 mov cl, al ; cl=al=0
560040DBAD 8BC1 mov eax, ecx ; eax=0
570040DBAF 99 cdq ; edx=0
580040DBB0 F73D 58264600 idiv dword ptr [462658] ; eax=eax/3E=0, edx=eax%3E=0
590040DBB6 8A82 60CA4600 mov al, byte ptr [edx+46CA60] ; al=chr[edx]='a'
60; 46CA60: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ, 记为 char chr[62];
610040DBBC 8B4D F4 mov ecx, dword ptr [ebp-C] ; eax=i=3
620040DBBF 8B55 10 mov edx, dword ptr [ebp+10] ; edx=buffer
630040DBC2 880411 mov byte ptr [ecx+edx], al ; buffer[i]=al
64; 小结(i 奇的时候)
65; r1 = i % length;
66; r2 = (i+3) % length;
67; offset = (username[r]^username[r2]) % 0x5E;
68; buffer[i] = chr[offset];
690040DBC5 E9 32000000 jmp 0040DBFC
700040DBCA 8B45 F8 mov eax, dword ptr [ebp-8] ; eax=r2=0
710040DBCD 8B4D 08 mov ecx, dword ptr [ebp+8] ; ecx=username
720040DBD0 0FBE0408 movsx eax, byte ptr [eax+ecx] ; eax=username[r2]
730040DBD4 8B4D FC mov ecx, dword ptr [ebp-4] ; ecx=r1
740040DBD7 8B55 08 mov edx, dword ptr [ebp+8] ; edx=username
750040DBDA 0FBE0C11 movsx ecx, byte ptr [ecx+edx] ; eax=username[r1]
760040DBDE 23C1 and eax, ecx ; eax=username[r2]&username[r1]
770040DBE0 33C9 xor ecx, ecx
780040DBE2 8AC8 mov cl, al
790040DBE4 8BC1 mov eax, ecx ; eax 取最后两位
800040DBE6 99 cdq
810040DBE7 F73D 58264600 idiv dword ptr [462658]
820040DBED 8A82 60CA4600 mov al, byte ptr [edx+46CA60]
830040DBF3 8B4D F4 mov ecx, dword ptr [ebp-C]
840040DBF6 8B55 10 mov edx, dword ptr [ebp+10]
850040DBF9 880411 mov byte ptr [ecx+edx], al ; buffer[i]=al
86; 小结(i 偶的时候)
87; r1 = i % length;
88; r2 = (i+3) % length;
89; offset = (username[r]&username[r2]) % 0x5E;
90; buffer[i] = chr[offset];
910040DBFC E9 5CFFFFFF jmp 0040DB5D ; 循环尾
920040DC01 6A 00 push 0
930040DC03 E8 D8390100 call 004215E0 ; 生成一个随机值
940040DC08 83C4 04 add esp, 4
950040DC0B 50 push eax ; 这个值作为下面的用的值
960040DC0C E8 8F390100 call 004215A0 ; 仅仅设置一个初始值而已,看了好久,太浪费时间了
970040DC11 83C4 04 add esp, 4
980040DC14 E8 97390100 call 004215B0
990040DC19 99 cdq
1000040DC1A F73D 58264600 idiv dword ptr [462658]
1010040DC20 8A82 60CA4600 mov al, byte ptr [edx+46CA60]
1020040DC26 8B4D 10 mov ecx, dword ptr [ebp+10]
1030040DC29 8841 12 mov byte ptr [ecx+12], al ; 加一个字符(但是注册码仅仅比较前面 18 位,这些是没用的)
1040040DC2C E8 7F390100 call 004215B0
1050040DC31 99 cdq
1060040DC32 F73D 58264600 idiv dword ptr [462658]
1070040DC38 8A82 60CA4600 mov al, byte ptr [edx+46CA60]
1080040DC3E 8B4D 10 mov ecx, dword ptr [ebp+10]
1090040DC41 8841 13 mov byte ptr [ecx+13], al ; 再加一个字符
1100040DC44 E8 67390100 call 004215B0
1110040DC49 99 cdq
1120040DC4A F73D 58264600 idiv dword ptr [462658]
1130040DC50 8A82 60CA4600 mov al, byte ptr [edx+46CA60]
1140040DC56 8B4D 10 mov ecx, dword ptr [ebp+10]
1150040DC59 8841 14 mov byte ptr [ecx+14], al ; 再加一个字符
1160040DC5C E8 4F390100 call 004215B0
1170040DC61 99 cdq
1180040DC62 F73D 58264600 idiv dword ptr [462658]
1190040DC68 8A82 60CA4600 mov al, byte ptr [edx+46CA60]
1200040DC6E 8B4D 10 mov ecx, dword ptr [ebp+10]
1210040DC71 8841 15 mov byte ptr [ecx+15], al ; 再加一个字符
1220040DC74 8B45 10 mov eax, dword ptr [ebp+10]
1230040DC77 C640 16 00 mov byte ptr [eax+16], 0 ; 结束符
1240040DC7B 5F pop edi
1250040DC7C 5E pop esi
1260040DC7D 5B pop ebx
1270040DC7E C9 leave
1280040DC7F C3 retn
与最后面的 4 位生成有关的是 004215E0、004215A0、004215B0 这三个函数。由于经验不足,我在里面分析了好久。后来搞累了,随便乱输最后 4 位,发现总是可以的。不断的看软件自己生成的注册码,最后 4 位总是不一样的。然后回过头来看注册码比较的地方,是无视最后 4 位的,才知道那 4 位无关紧要。再再再后来用 IDA 看,原来是 _time、_srand、_rand 这三个函数……
把那些白看了的也贴出来吧
1{
2 004215E0 83EC 10 sub esp, 10
3 004215E3 8D4424 00 lea eax, dword ptr [esp] ; buffer
4 004215E7 50 push eax ; pLocaltime
5 004215E8 FF15 10274700 call dword ptr [<&KERNEL32.GetLocalTime> ; GetLocalTime
6 ; D8 07 06 00 06 00 07 00 0F 00 2D 00 03 00 2C 03
7 ; typedef struct _SYSTEMTIME
8 ; {
9 ; WORD wYear; // 0x07D8=2008
10 ; WORD wMonth; // 0x0006=6
11 ; WORD wDayOfWeek; // 0x0007=6(Sat.)
12 ; WORD wDay; // 0x0007=7
13 ; WORD wHour; // 0x000F=15)
14 ; WORD wMinute; // 0x002D=45
15 ; WORD wSecond; // 0x0003=3
16 ; WORD wMilliseconds; // 0x032C=812 (15:45:03.812)
17 ; } SYSTEMTIME, *PSYSTEMTIME;
18 004215EE 8B4424 0C mov eax, dword ptr [esp+C]
19 004215F2 25 FFFF0000 and eax, 0FFFF ; 秒 00000023
20 004215F7 50 push eax
21 004215F8 33C0 xor eax, eax
22 004215FA 66:8B4424 0E mov ax, word ptr [esp+E] ; 分钟 00000021
23 004215FF 50 push eax
24 00421600 8B4424 10 mov eax, dword ptr [esp+10]
25 00421604 25 FFFF0000 and eax, 0FFFF ; 小时 00000011
26 00421609 50 push eax
27 0042160A 33C0 xor eax, eax
28 0042160C 66:8B4424 12 mov ax, word ptr [esp+12] ; 日期 00000007
29 00421611 50 push eax
30 00421612 33C0 xor eax, eax
31 00421614 66:8B4424 12 mov ax, word ptr [esp+12] ; 月份 00000006
32 00421619 50 push eax
33 0042161A 8B4424 14 mov eax, dword ptr [esp+14] ; 年份 000007D8
34 0042161E 25 FFFF0000 and eax, 0FFFF
35 00421623 50 push eax
36 00421624 E8 37100000 call 00422660
37 {
38 00422660 83EC 24 sub esp, 24
39 00422663 53 push ebx
40 00422664 56 push esi
41 00422665 8B7424 30 mov esi, dword ptr [esp+30] ; 年份, esi=000007D8
42 00422669 57 push edi
43 0042266A 55 push ebp
44 0042266B 81EE 6C070000 sub esi, 76C ; esi=esi-0000076C(1900)=0000006C(108)
45 ; 记为 years
46 00422671 83FE 46 cmp esi, 46 ; 当前时间 1970 以前, eax=-1, 跳出
47 00422674 0F8C AE000000 jl 00422728
48 0042267A 81FE 8A000000 cmp esi, 8A ; 当前时间 2038 以后, 处理同上
49 00422680 0F8F A2000000 jg 00422728
50 00422686 8B5C24 3C mov ebx, dword ptr [esp+3C] ; ebx=月份=00000006
51 0042268A 8B2C9D D4A743 mov ebp, dword ptr [ebx*4+43A7D4] ; ebp=00000096
52 ; 0043A7D4+1*4: FFFFFFFF -1
53 ; 0043A7D4+2*4: 0000001E 30 +31
54 ; 0043A7D4+3*4: 0000003A 58 +28
55 ; 0043A7D4+4*4: 00000059 89 +31
56 ; 0043A7D4+5*4: 00000077 119 +30
57 ; 0043A7D4+6*4: 00000096 150 +31
58 ; 0043A7D4+7*4: 000000B4 180 +30
59 ; 0043A7D4+8*4: 000000D3 211 +31
60 ; 0043A7D4+9*4: 0000016C 242 +31
61 ; 0043A7D4+A*4: 00000110 272 +30
62 ; 0043A7D4+B*4: 0000012F 303 +31
63 ; 0043A7D4+C*4: 0000014D 333 +30
64 00422691 036C24 40 add ebp, dword ptr [esp+40] ; 加上日期, ebp=0000009D, 一年中的第几天
65 00422695 F7C6 03000000 test esi, 3 ; 年份是否为 4 的倍数
66 0042269B 75 06 jnz short 004226A3
67 0042269D 83FB 02 cmp ebx, 2 ; 月份是否为 2
68 004226A0 7E 01 jle short 004226A3
69 004226A2 45 inc ebp ; 加上一天, ebp=0000009E, 记为 yday
70 004226A3 E8 F8420000 call 004269A0
71 {
72 004269A0 833D 64A74300 cmp dword ptr [43A764], 0 ; [43A764]=1
73 004269A7 75 28 jnz short 004269D1 ; 直接跳出……忽悠人的?
74 004269A9 6A 0B push 0B
75 004269AB E8 F0C4FFFF call 00422EA0
76 004269B0 83C4 04 add esp, 4
77 004269B3 833D 64A74300 cmp dword ptr [43A764], 0
78 004269BA 75 0B jnz short 004269C7
79 004269BC E8 3F000000 call 00426A00
80 004269C1 FF05 64A74300 inc dword ptr [43A764]
81 004269C7 6A 0B push 0B
82 004269C9 E8 42C5FFFF call 00422F10
83 004269CE 83C4 04 add esp, 4
84 004269D1 C3 retn
85 }
86 004226A8 8D14F6 lea edx, dword ptr [esi+esi*8] ; edx=esi*9=0000033CC(972)=years*9
87 004226AB 8D04D6 lea eax, dword ptr [esi+edx*8] ; eax==esi*49h=00001ECC(7884)=years*73d
88 004226AE 8B4C24 44 mov ecx, dword ptr [esp+44] ; ecx=小时=11, 记为 hour
89 004226B2 8D1480 lea edx, dword ptr [eax+eax*4] ; edx=eax*5=000099FC(39420)=years*365d
90 004226B5 8D46 FF lea eax, dword ptr [esi-1] ; eax=0000006B(107)=years-1
91 004226B8 03D5 add edx, ebp ; edx=00009A9A=years*366d-1
92 004226BA 83E0 FC and eax, FFFFFFFC ; eax 低两位变 0, =(years-1)-(years-1)%4
93 004226BD 8D1490 lea edx, dword ptr [eax+edx*4] ; edx=(years*366-1)*4+((years-1)-(years-1)%4)
94 004226C0 8D3C52 lea edi, dword ptr [edx+edx*2] ; edi=(years*366-1)*12+((years-1)-(years-1)%4)*3
95 004226C3 8D1479 lea edx, dword ptr [ecx+edi*2] ; edx=(years*366-1)*24+((years-1)-(years-1)%4)*6+hour
96 004226C6 C1E2 02 shl edx, 2 ; edx=(years*366-1)*6+(years-1)/4*6+hour/4
97 004226C9 8D3C52 lea edi, dword ptr [edx+edx*2] ; edi=(years*366-1)*18+(years-1)/4*18+hour/4*3
98 004226CC 8B4424 4C mov eax, dword ptr [esp+4C] ; eax=秒, 记为 second
99 004226D0 8D14BF lea edx, dword ptr [edi+edi*4] ; edx=(years*366-1)*90+(years-1)/4*90+hour/4*15
100 004226D3 896C24 2C mov dword ptr [esp+2C], ebp ; [esp+2C]=yday
101 004226D7 035424 48 add edx, dword ptr [esp+48] ; edx+=分钟, mimute
102 ; edx=(years*366-1)*90+(years-1)/4*90+hour/4*15+minute
103 004226DB 897424 24 mov dword ptr [esp+24], esi ; [esp+24]=years
104 004226DF C1E2 02 shl edx, 2 ; edx=(years*366-1)*90/4+(years-1)/4*90/4+hour/4*15/4+minute/4
105 004226E2 4B dec ebx ; yday=yday-1
106 004226E3 8D3C52 lea edi, dword ptr [edx+edx*2] ; edi=(years*366-1)*90/4*3+(years-1)/4*90/4*3+hour/4*15/4*3+minute/4*3
107 004226E6 895C24 20 mov dword ptr [esp+20], ebx ; [esp+20]=yday-1
108 004226EA 894C24 18 mov dword ptr [esp+18], ecx ; [esp+18]=hour
109 004226EE 8D14BF lea edx, dword ptr [edi+edi*4] ; edx=(years*366-1)*90/4*15+(years-1)/4*90/4*15+hour/4*15/4*15+minute/4*15
110 004226F1 0315 70A74300 add edx, dword ptr [43A770] ; [43A770]=FFFF8F80
111 ; edx=(years*366-1)*90/4*15+(years-1)/4*90/4*15+hour/4*15/4*15+minute/4*15+0xFFFF8F80
112 004226F7 833D 74A74300 cmp dword ptr [43A774], 0 ; [43A774]=00000000
113 004226FE 8DBC02 808155 lea edi, dword ptr [edx+eax+7C558180]
114 ; edi=(years*366-1)*90/4*15+(years-1)/4*90/4*15+hour/4*15/4*15+minute/4*15+0xFFFF8F80+second+0x7C558180
115 00422705 74 17 je short 0042271E
116 00422707 8D4424 10 lea eax, dword ptr [esp+10]
117 0042270B 50 push eax
118 0042270C E8 6F450000 call 00426C80
119 00422711 83C4 04 add esp, 4
120 00422714 85C0 test eax, eax
121 00422716 74 06 je short 0042271E
122 00422718 81EF 100E0000 sub edi, 0E10
123 0042271E 8BC7 mov eax, edi
124 00422720 5D pop ebp
125 00422721 5F pop edi
126 00422722 5E pop esi
127 00422723 5B pop ebx
128 00422724 83C4 24 add esp, 24
129 00422727 C3 retn
130 00422728 B8 FFFFFFFF mov eax, -1
131 0042272D 5D pop ebp
132 0042272E 5F pop edi
133 0042272F 5E pop esi
134 00422730 5B pop ebx
135 00422731 83C4 24 add esp, 24
136 00422734 C3 retn
137 }
138 00421629 8B4C24 2C mov ecx, dword ptr [esp+2C]
139 0042162D 83C4 18 add esp, 18
140 00421630 85C9 test ecx, ecx
141 00421632 74 02 je short 00421636
142 00421634 8901 mov dword ptr [ecx], eax
143 00421636 83C4 10 add esp, 10
144 00421639 C3 retn
145}
补丁&注册机。(仅用于学习研究,请下载后24 小时内删除。)
首发:https://blog.csdn.net/cnStreamlet/article/details/2521622